added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / tools / nmake / command.cpp
blob5085d9c6fcd526bbd2b4c06109d65e44d3398cf8
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
14 // ==--==
15 // COMMAND.C - NMAKE 'command line' handling routines
17 // Purpose:
18 // Module contains routines to handle NMAKE 'command line' syntax. NMAKE can be
19 // optionally called by using the syntax 'NMAKE @commandfile'. This allows more
20 // flexibility and preents a way of getting around DOS's 128-byte limit on the
21 // length of a command line. Additionally, it saves keystrokes for frequently
22 // run commands for NMAKE.
24 #include "precomp.h"
25 #ifdef _MSC_VER
26 #pragma hdrstop
27 #endif
29 void addArgument(char*,unsigned,char***);
30 void processLine(char*,unsigned*,char***);
31 void tokenizeLine(char*,unsigned*,char***);
33 // readCommandFile()
35 // arguments: name pointer to name of command file to read
37 // actions: opens command file
38 // reads in lines and calls processLine() to
39 // break them into tokens and to build
40 // an argument vector (a la argv[])
41 // calls parseCommandLine() recursively to process
42 // the accumulated "command line" arguments
43 // frees space used by the arg vector
45 // modifies: makeFiles in main() by modifying contents of parameter list
46 // makeTargets in main() by modifying contents of targets parameter
47 // buf global buffer
49 // notes: function is not ANSI portable because it uses fopen()
50 // with "rt" type and text mode is a Microsoft extension
53 void
54 readCommandFile(
55 char *name
58 char *s, // buffer
59 **vector; // local versions of arg vector
60 unsigned count = 0; // count
61 size_t n;
63 if (!(file = FILEOPEN(name,"rt")))
64 makeError(0,CANT_OPEN_FILE,name);
65 vector = NULL; // no args yet
66 while (fgets(buf,MAXBUF,file)) {
67 n = _tcslen(buf);
69 // if we didn't get the whole line, OR the line ended with a backSlash
71 if ((n == MAXBUF-1 && buf[n-1] != '\n') ||
72 (buf[n-1] == '\n' && buf[n-2] == '\\')
73 ) {
74 if (buf[n-2] == '\\' && buf[n-1] == '\n') {
75 // Replace \n by \0 and \\ by a space; Also reset length
76 buf[n-1] = '\0';
77 buf[n-2] = ' ';
78 n--;
80 s = makeString(buf);
81 getRestOfLine(&s,&n);
82 } else
83 s = buf;
85 processLine(s,&count,&vector); // separate into args
86 if (s != buf)
87 FREE(s);
90 if (fclose(file) == EOF)
91 makeError(0, ERROR_CLOSING_FILE, name);
93 parseCommandLine(count,vector); // evaluate the args
94 while (count--) // free the arg vector
95 if(vector[count])
96 FREE(vector[count]); // NULL entries mean that the space the
97 } // entry used to pt to is still in use
100 // getRestOfLine()
102 // arguments: s pointer to readCommandFile()'s buffer
103 // holding line so far
104 // n pointer to readCommandFile()'s count of
105 // the chars in *s
107 // actions: keeps reading in text until it sees a newline
108 // or the end of file
109 // reallocs space for the old buffer plus the
110 // contents of the new buffer each time
111 // appends new buffer's text to existing text
113 // modifies: s readCommandFile()'s text buffer by realloc'ing
114 // more space for incoming text
115 // n readCommandFile()'s count of bytes in s
116 // buf global buffer
118 void
119 getRestOfLine(
120 char *s[],
121 size_t *n
124 size_t temp;
125 char *t;
127 t = buf;
128 while ((*s)[*n-1] != '\n') { // get rest of line
129 if (!fgets(t,MAXBUF,file))
130 break; // we hit EOF
131 temp = _tcslen(t);
132 if (t[temp-2] == '\\' && t[temp-1] == '\n') {
133 //Replace \n by \0 and \\ by a space; Also reset length
134 t[temp-1] = '\0';
135 t[temp-2] = ' ';
137 temp = *n;
138 *n += _tcslen(t);
139 *s = (char *) REALLOC(*s,*n+1); // + 1 for NULL byte
140 if (!*s)
141 makeError(line, MACRO_TOO_LONG);
142 _tcscpy(*s+temp,t);
151 void
152 processLine(
153 char *s,
154 unsigned *count,
155 char **vector[]
158 char *t;
159 char *u;
160 size_t m;
161 size_t n;
162 BOOL allocFlag = FALSE;
164 if (!(t = _tcschr(s,'"'))) { // no quoted strings,
165 tokenizeLine(s,count,vector); // just standard fare
166 } else {
167 // There are two kinds of situations in which quotes can occur:
168 // 1. "FOO = bar baz"
169 // 2. FOO="bar baz"
171 if ((t == s) || (*(t-1) != '=')) {
172 // Case 1 above
173 *t++ = '\0'; // quoted macrodef
174 tokenizeLine(s,count,vector); // get tokens before "
175 } else {
176 // Case 2 above
177 *t-- = ' ';
178 for (u = t; u > s; --u) // find the beginning of the macro name
179 if (*u == ' ' || *u == '\t' || *u == '\n')
180 break;
182 if (u != s) {
183 *u++ = '\0';
184 tokenizeLine(s, count, vector);
187 t = u;
190 n = _tcslen(t);
191 for (u = t; *u; ++u) { // look for closing "
192 if (*u == '"') { // need " and not ""
193 if (*(u+1) == '"') {
194 _tcscpy(u,u+1);
195 continue;
197 *u++ = '\0'; // terminate macrodef
198 addArgument(t,*count,vector); // treat as one arg
199 ++*count;
200 processLine(u+1,count,vector); // recurse on rest of line
201 break;
202 } // TAIL RECURSION
204 if ((*u == '\\')
205 && WHITESPACE(*(u-1))
206 && (*(u+1) == '\n')) { // \n always last char
207 *u = '\0'; // 2 chars go to 1
208 m = (n = n-2); // adjust length count
209 if (!allocFlag) {
210 allocFlag = TRUE;
211 t = makeString(t);
213 getRestOfLine(&t,&n); // get some more text
214 u = t + m ; // reset u & continue looping
218 if (u == t + n) { // if at end of line
219 makeError(0,SYNTAX_NO_QUOTE); // and no ", error
222 if (allocFlag) {
223 FREE(t);
229 // tokenizeLine()
231 // arguments: s pointer to readCommandFile()'s buffer
232 // holding "command line" to be tokenized
233 // count pointer to readCommandFile()'s count of
234 // "command line" arguments seen so far
235 // vector pointer to readCommandFile()'s vector of
236 // pointers to character strings
238 // actions: breaks the line in s into tokens (command line
239 // arguments) delimited by whitespace
240 // adds each token to the argument vector
241 // adjusts the argument counter
243 // modifies: vector readCommandFile()'s vector of pointers to
244 // "command line argument" strings (by modifying
245 // the contents of the parameter pointer, vector)
246 // count readCommandFile()'s count of the arguments in
247 // the vector (by modifying the contents of the
248 // parameter pointer, count)
250 // If the user ever wants '@' to be part of an argument in a command file,
251 // he has to enclose that argument in quotation marks.
253 void
254 tokenizeLine( // gets args delimited
255 char *s, // by whitespace and
256 unsigned *count, // constructs an arg
257 char **vector[] // vector
260 char *t;
262 if ((t = _tcschr(s,'\\'))) {
263 if (WHITESPACE(*(t-1)) && (*(t+1) == '\n')) {
264 *t = '\0';
268 for (t = _tcstok(s," \t\n"); t; t = _tcstok(NULL," \t\n")) {
269 if (*t == '@') {
270 makeError(0,SYNTAX_CMDFILE,t+1);
271 break; // should we keep on parsing here?
273 addArgument(t,*count,vector);
274 ++*count;
279 // addArgument()
281 // arguments: s pointer to text of argument to be added
282 // to the "command line argument" vector
283 // count pointer to readCommandFile()'s count of
284 // "command line" arguments seen so far
285 // vector pointer to readCommandFile()'s vector of
286 // pointers to character strings
288 // actions: allocates space in the vector for the new argument
289 // allocates space for argument string
290 // makes vector entry point to argument string
292 // modifies: vector readCommandFile()'s vector of pointers to
293 // "command line argument" strings (by modifying
294 // the contents of the parameter pointer, vector)
295 // (count gets incremented by caller)
297 // To keep from fragmenting memory by doing many realloc() calls for very
298 // small amounts of space, we get memory in small chunks and use that until
299 // it is depleted, then we get another chunk . . . .
301 void
302 addArgument( // puts s in vector
303 char *s,
304 unsigned count,
305 char **vector[]
308 if (!(*vector)) {
309 *vector = (char**) allocate(CHUNKSIZE*sizeof(char*));
310 } else if (!(count % CHUNKSIZE)) {
311 *vector = (char**) REALLOC(*vector,(count+CHUNKSIZE)*sizeof(char*));
312 if (!*vector) {
313 makeError(0,OUT_OF_MEMORY);
316 (*vector)[count] = makeString(s);